package com.link.base.base.product.service;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.link.base.base.product.dao.mybatis.mapper.PartsCostTempMapper;
import com.link.base.base.product.model.PartsCostTempData;
import com.link.base.user.model.CoreUser;
import com.link.core.util.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PartsCostTempListener extends AnalysisEventListener<PartsCostTempData> {

    private static final Logger logger = LogManager.getLogger(PartsCostTempListener.class);

    private PartsCostTempMapper partsCostTempMapper;

    private CoreUser user;

    List<PartsCostTempData> list = new ArrayList<>();

    private int BATCH_COUNT = 100;

    private int middleBatchLen = 20;

    private int COUNT_NUM = 0;

    private Long projectId;

    private StringBuilder errCountNum = new StringBuilder("");

    public PartsCostTempListener(PartsCostTempMapper partsCostTempMapper, CoreUser user, Long projectId) {
        this.partsCostTempMapper = partsCostTempMapper;
        this.user = user;
        this.projectId = projectId;
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        /*
        count 记录模板表头有几个，用以判断用户导入的表格是否和模板完全一致
        如果用户导入表格较模板的表头多，但其余符合模板，这样不影响则不需要
         */
        int count = 0;
        // 获取数据实体的字段列表
        Field[] fields = PartsCostTempData.class.getDeclaredFields();
        // 遍历字段进行判断
        for (Field field : fields) {
            // 获取当前字段上的ExcelProperty注解信息
            ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
            // 判断当前字段上是否存在ExcelProperty注解
            if (fieldAnnotation != null) {
                ++count;
                // 存在ExcelProperty注解则根据注解的index索引到表头中获取对应的表头名
                String headName = headMap.get(fieldAnnotation.index());
                // 判断表头是否为空或是否和当前字段设置的表头名不相同
                if (StringUtils.isNull(headName) || !headName.equals(fieldAnnotation.value()[0])) {
                    // 如果为空或不相同，则抛出异常不再往下执行
                    throw new RuntimeException("模板错误，请检查导入模板");
                }
            }
        }
        // 判断用户导入表格的标题头是否完全符合模板
        if (count != headMap.size()) {
            throw new RuntimeException("模板错误，请检查导入模板");
        }
    }

    @Override
    public void invoke(PartsCostTempData partsCostTempData, AnalysisContext analysisContext) {
        // 去掉头的行数
        Integer total = analysisContext.getTotalCount() - 1;
        if (total <= 0) {
            return;
        }
        // 初始化数据
        partsCostTempData.setCreatedBy(user.getId());
        partsCostTempData.setLastUpdatedBy(user.getId());
        partsCostTempData.setCorpid(user.getCorpid());
        partsCostTempData.setOrgId(user.getOrgId());
        partsCostTempData.setPostnId(user.getPostnId());
        partsCostTempData.setProjectId(projectId);

        // 物料层级处理
        String wlmc = partsCostTempData.getWlmc();
        if (!StringUtils.isNull(wlmc)) {
            String[] arr = wlmc.split("-");
            int len = arr.length;
            if (len == 2) {
                partsCostTempData.setWlmcHead(arr[0]);
                partsCostTempData.setWlmcTail(arr[1]);
            }
            if (len == 1) {
                partsCostTempData.setWlmcHead(arr[0]);
                partsCostTempData.setWlmcTail(null);
            }
        }
        // 添加到集合
        list.add(partsCostTempData);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        try {
            this.saveData();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("数据读取完成!");
    }

    /**
     * 保存
     * @throws Exception
     */
    private void saveData() throws Exception {
        if (null == list || list.size() == 0) {
            return;
        }
        // 计数器
        int count = 1;
        List<PartsCostTempData> toInsertPartsCostTempDataList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        for (PartsCostTempData partsCostTempData : list) {
            toInsertPartsCostTempDataList.add(partsCostTempData);
            ids.add(partsCostTempData.getId());
            if (count == BATCH_COUNT) {
                try {
                    partsCostTempMapper.batchInserts(toInsertPartsCostTempDataList);
                } catch (Exception e) {
                    this.middleImport(toInsertPartsCostTempDataList);
                }
                count = 1;
                toInsertPartsCostTempDataList.clear();
                ids.clear();
            } else {
                count++;
            }
        }
        // 扫尾
        if (count > 0) {
            try {
                // 批量插入
                partsCostTempMapper.batchInserts(toInsertPartsCostTempDataList);
            } catch (Exception e) {
                try {
                    this.middleImport(toInsertPartsCostTempDataList);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            // 重新计数
            count = 1;
            // 清空list，重新塞数据
            toInsertPartsCostTempDataList.clear();
            ids.clear();
        }
    }





    private void middleImport(List<PartsCostTempData> partsCostTempDataList) throws Exception {
        // 计数器
        int count = 1;
        List<PartsCostTempData> toInsertZyAccountTempList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        for (PartsCostTempData partsCostTempData : partsCostTempDataList) {
            toInsertZyAccountTempList.add(partsCostTempData);
            ids.add(partsCostTempData.getId());
            if (count == middleBatchLen) {
                try {
                    // 批量插入
                    partsCostTempMapper.batchInserts(toInsertZyAccountTempList);
                } catch (Exception e) {
                    this.singleInsert(toInsertZyAccountTempList);
                }
                count = 1;
                toInsertZyAccountTempList.clear();
                ids.clear();
            } else {
                count++;
            }
        }
        // 扫尾
        if (count > 0) {
            try {
                // 批量插入
                partsCostTempMapper.batchInserts(toInsertZyAccountTempList);
            } catch (Exception e) {
                this.singleInsert(toInsertZyAccountTempList);
            }
            // 重新计数
            count = 1;
            // 清空list，重新塞数据
            toInsertZyAccountTempList.clear();
            ids.clear();
        }
    }

    private void singleInsert(List<PartsCostTempData> partsCostTempList) {
        for (PartsCostTempData partsCostTempDataTemp : partsCostTempList) {
            try {
                partsCostTempDataTemp.setCheckStatus("New");
                partsCostTempMapper.addData(partsCostTempDataTemp);
            } catch (Exception e) {
                e.printStackTrace();
                String errorMsg = e.getMessage();
                if (!StringUtils.isNull(errorMsg) && errorMsg.length() > 1000) {
                    errorMsg = errorMsg.substring(0, 1000);
                }
                partsCostTempDataTemp.setErrorMsg(errorMsg);
                partsCostTempDataTemp.setCheckStatus("UPLOAD_FAIL");
                try {
                    partsCostTempMapper.addErrorData(partsCostTempDataTemp);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private boolean isLineNullValue(Object data) {
        if (data instanceof String) {
            return StringUtils.isNull((String)data);
        }
        try {
            List<Field> fields = Arrays.stream(data.getClass().getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(ExcelProperty.class))
                    .collect(Collectors.toList());
            List<Boolean> lineNullList = new ArrayList<>(fields.size());
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(data);
                if (StringUtils.isNull((String)value)) {
                    lineNullList.add(Boolean.TRUE);
                } else {
                    lineNullList.add(Boolean.FALSE);
                    return false;
                }
            }
            return lineNullList.stream().allMatch(Boolean.TRUE::equals);
        } catch (Exception e) {
            logger.error("读取数据行[{}]解析失败: {}", data, e.getMessage());
        }
        return true;
    }
}
